package edu.xhu.biliuser.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.json.JSONUtil;
import cn.hutool.jwt.Claims;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import edu.xhu.api.id.IdClient;
import edu.xhu.biliuser.mapper.BiliUserConfigMapper;
import edu.xhu.biliuser.mapper.BiliUserInfoMapper;
import edu.xhu.model.biliuser.dtos.LoginAndRegisterDto;
import edu.xhu.model.biliuser.dtos.RatioDto;
import edu.xhu.model.biliuser.enums.*;
import edu.xhu.model.biliuser.pojos.BiliUserConfig;
import edu.xhu.model.biliuser.pojos.BiliUserInfo;
import edu.xhu.model.biliuser.vos.BiliUserConfigVo;
import edu.xhu.model.biliuser.vos.BiliUserInfoVo;
import edu.xhu.model.biliuser.vos.BiliUserVo;
import edu.xhu.model.common.dtos.ResponseResult;
import edu.xhu.model.common.enums.AppHttpCodeEnum;
import edu.xhu.model.biliuser.pojos.BiliUser;
import edu.xhu.biliuser.mapper.BiliUserMapper;
import edu.xhu.biliuser.service.BiliUserService;
import edu.xhu.utils.common.AppJwtUtil;
import edu.xhu.utils.common.SaltGenerator;
import edu.xhu.utils.thread.BiliUserThreadLocalUtil;
import edu.xhu.utils.validator.CodeValidator;
import edu.xhu.utils.validator.PhoneValidator;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;


@Service
@RequiredArgsConstructor
@Slf4j
public class BiliUserServiceImpl extends ServiceImpl<BiliUserMapper, BiliUser> implements BiliUserService {

    private final IdClient idClient;

    private final BiliUserConfigMapper biliUserConfigMapper;

    private final BiliUserInfoMapper biliUserInfoMapper;

    private final BiliUserMapper biliUserMapper;

    private final HttpServletRequest request;

    /**
     * 网页端登录功能:手机号,账号登录两种方式
     */
    @Override
    public ResponseResult<?> login(LoginAndRegisterDto dto) {

        //1.1 根据手机号和账号查询用户信息
        BiliUser biliUser = getOne(Wrappers.<BiliUser>lambdaQuery().eq(BiliUser::getPhone, dto.getAccount()));
        if (biliUser == null) {
            //如果手机号不是,采用账号方式登录
            biliUser = getOne(Wrappers.<BiliUser>lambdaQuery().eq(BiliUser::getUserName, dto.getAccount()));
            if (biliUser == null) {
                return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST, "用户信息不存在");
            }
        }
        //1.2 比对密码
        String salt = biliUser.getSalt();
        String password = dto.getPassword();
        String pswd = DigestUtils.md5DigestAsHex((password + salt).getBytes());
        if (!pswd.equals(biliUser.getPassword())) {
            return ResponseResult.errorResult(AppHttpCodeEnum.LOGIN_PASSWORD_ERROR);
        }
        //1.3 返回数据  jwt  user
        String token = AppJwtUtil.getToken(biliUser.getUserId());
        Map<String, Object> map = new HashMap<>();
        map.put("token", token);
        biliUser.setSalt("");
        biliUser.setPassword("");


        //1.4 返回用户信息
        BiliUserVo biliUserVo = BeanUtil.copyProperties(biliUser, BiliUserVo.class);
        BiliUserInfo biliUserInfo = biliUserInfoMapper.selectById(biliUser.getUserId());
        if (biliUserInfo == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST, "用户信息不存在！");
        }
        BiliUserConfig biliUserConfig = biliUserConfigMapper.selectById(biliUser.getUserId());
        if (biliUserConfig == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST, "用户配置不存在！");
        }
        BiliUserInfoVo biliUserInfoVo = BeanUtil.copyProperties(biliUserInfo, BiliUserInfoVo.class);
        BiliUserConfigVo biliUserConfigVo = BeanUtil.copyProperties(biliUserConfig, BiliUserConfigVo.class);
        map.put("biliuser", biliUserVo);
        map.put("biliuserinfo", biliUserInfoVo);
        map.put("biliuserconfig", biliUserConfigVo);
        return ResponseResult.okResult(map);
    }

    /**
     * 网页端注册功能:绑定用手机号注册,注册默认生成账号,默认用账号名为昵称
     * 一定要加事务,进行回滚
     * 注册逻辑:
     * 1.校验格式
     * 2.暂无短信逻辑,这里默认生成密码,随机盐加密
     * 3.生成一个bili全局唯一账户号,同时用户的nickName也是该账户号
     * 4.处理用户三张基本表:bili-user,bili-user-info,bili-user-config
     * 5.TODO-分布式事务
     */
    @Override
    @Transactional
    public ResponseResult<?> register(LoginAndRegisterDto dto) {
        //校验手机号格式
        if (!PhoneValidator.validate(dto.getAccount())) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_PATTERN_ERROR, "手机号格式不正确！");
        }
        //校验是否注册过
        BiliUser biliUser = getOne(Wrappers.<BiliUser>lambdaQuery().eq(BiliUser::getPhone, dto.getAccount()));
        if (biliUser != null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_EXIST, "该手机号已被注册！");
        }
        //开始注册逻辑-先判断状态码
        ResponseResult<?> snowflakeDistributedId = idClient.getSnowflakeDistributedId();
        if (!CodeValidator.idValidator(snowflakeDistributedId)) {
            return ResponseResult.errorResult(snowflakeDistributedId.getCode(), "获取id失败！");
        }
        //获取分布式id和随机盐
        Long id = (Long) snowflakeDistributedId.getData();
        String salt = SaltGenerator.generateSalt();
        //构建数据-插入数据,bili-user
        if (
                !save(new BiliUser(id
                        , salt
                        , DigestUtils.md5DigestAsHex((dto.getPassword() + salt).getBytes())
                        , "bili_" + IdUtil.simpleUUID()
                        , dto.getAccount()
                        , new Date()
                        , new Date()
                        , new Date()
                        , "ip", "ip"))) {
            return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR, "保存用户失败！");
        }
        //插入,bili-user-config
        if (biliUserConfigMapper.insert(new BiliUserConfig(id
                , AuthType.NORMAL.getCode()
                , MegaType.COMMON.getCode()
                , ""
                , new Date()
                , 1)) < 1) {
            return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR, "保存用户配置失败！");
        }
        //插入,bili-user-info
        if (biliUserInfoMapper.insert(new BiliUserInfo(id
                , "bili_" + PhoneValidator.maskPhoneNumber(dto.getAccount())
                , "默认头像地址"
                , LevelEnum.LEVEL_ZERO.getLevel()
                , ExperienceEnum.LOGIN.getExperience()
                , new Date())) < 1) {
            return ResponseResult.errorResult(AppHttpCodeEnum.SERVER_ERROR, "保存用户信息失败！");
        }
        return ResponseResult.okResult("注册成功");
    }

    @Override
    public void logout() {
        return ;
    }

    @Override
    public ResponseResult<?> personalInfo() {
        BiliUser currentUser = BiliUserThreadLocalUtil.getUser();
        BiliUser biliUser = getOne(Wrappers.<BiliUser>lambdaQuery().eq(BiliUser::getUserId, currentUser.getUserId()));
        if (biliUser == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST, "用户不存在！");
        }
        biliUser.setSalt("");
        biliUser.setPassword("");
        //返回用户信息
        Map<String, Object> map = new HashMap<>();
        BiliUserVo biliUserVo = BeanUtil.copyProperties(biliUser, BiliUserVo.class);
        BiliUserInfo biliUserInfo = biliUserInfoMapper.selectById(biliUser.getUserId());
        if (biliUserInfo == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST, "用户信息不存在！");
        }
        BiliUserConfig biliUserConfig = biliUserConfigMapper.selectById(biliUser.getUserId());
        if (biliUserConfig == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST, "用户配置不存在！");
        }
        BiliUserInfoVo biliUserInfoVo = BeanUtil.copyProperties(biliUserInfo, BiliUserInfoVo.class);
        BiliUserConfigVo biliUserConfigVo = BeanUtil.copyProperties(biliUserConfig, BiliUserConfigVo.class);
        map.put("biliuser", biliUserVo);
        map.put("biliuserinfo", biliUserInfoVo);
        map.put("biliuserconfig", biliUserConfigVo);
        return ResponseResult.okResult(map);
    }

    @Override
    public ResponseResult<?> onepersonalInfo(Long uid) {
        BiliUser biliUser = getOne(Wrappers.<BiliUser>lambdaQuery().eq(BiliUser::getUserId, uid));
        if (biliUser == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST, "用户不存在！");
        }
        biliUser.setSalt("");
        biliUser.setPassword("");
        //返回用户信息
        Map<String, Object> map = new HashMap<>();
        BiliUserVo biliUserVo = BeanUtil.copyProperties(biliUser, BiliUserVo.class);
        BiliUserInfo biliUserInfo = biliUserInfoMapper.selectById(biliUser.getUserId());
        if (biliUserInfo == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST, "用户信息不存在！");
        }
        BiliUserConfig biliUserConfig = biliUserConfigMapper.selectById(biliUser.getUserId());
        if (biliUserConfig == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST, "用户配置不存在！");
        }
        BiliUserInfoVo biliUserInfoVo = BeanUtil.copyProperties(biliUserInfo, BiliUserInfoVo.class);
        BiliUserConfigVo biliUserConfigVo = BeanUtil.copyProperties(biliUserConfig, BiliUserConfigVo.class);
        map.put("biliuser", biliUserVo);
        map.put("biliuserinfo", biliUserInfoVo);
        map.put("biliuserconfig", biliUserConfigVo);
        return ResponseResult.okResult(map);
    }

    @Override
    public ResponseResult<?> queryAllUserInfoByIds(List<Long> userIds) {
        List<Map<String, Object>> userAllInfos = biliUserMapper.queryAllUserInfoByIds(userIds);

        userAllInfos.forEach(item -> {
            item.remove("salt");
            item.remove("password");
        });

        if (userAllInfos == null || userAllInfos.size() == 0)
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST, "用户信息不存在");

        return ResponseResult.okResult(userAllInfos);
    }

    @Override
    public ResponseResult<?> queryUserInfoById(Long userId) {
        Map<String, Object> userAllInfo = biliUserMapper.queryUserInfoById(userId);


        if (userAllInfo == null || userAllInfo.size() == 0)
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST, "用户信息不存在");

        return ResponseResult.okResult(userAllInfo);
    }

    /**
     * 根据userId,获取一些响应比数据
     */
    @Override
    public ResponseResult<?> getRatioDataByUserId(Long userId) {
        BiliUserConfig userConfig = biliUserConfigMapper
                .selectOne(Wrappers.<BiliUserConfig>lambdaQuery()
                        .eq(BiliUserConfig::getUserId, userId)
                        .eq(BiliUserConfig::getUserState, UserStatus.NORMAL.getCode()));
        if (userConfig == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST, "配置不存在！");
        }
        BiliUserInfo userInfo = biliUserInfoMapper.selectById(userId);
        if (userInfo == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST, "信息不存在！");
        }
        RatioDto ratioDto = new RatioDto();
        BeanUtils.copyProperties(userConfig, ratioDto);
        BeanUtils.copyProperties(userInfo, ratioDto);
        return ResponseResult.okResult(JSONUtil.toJsonStr(ratioDto));
    }

    @Override
    public ResponseResult<?> getOneUserById(Long userId) {
        BiliUser biliUser = getOne(Wrappers.<BiliUser>lambdaQuery()
                .eq(BiliUser::getUserId, userId));
        if (biliUser == null) {
            return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        }
        return ResponseResult.okResult(JSONUtil.toJsonStr(biliUser));
    }
}
